/*------------------------------------------------------------------------
 *  Copyright (C) 2011  Luis M. de la Cruz
 *
 *  This file is part of TUNA
 *
 *  TUNA is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  TUNA is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ------------------------------------------------------------------------*/

#ifndef _SPARSEMATRIX_H_
#define _SPARSEMATRIX_H_

#include <iostream>
#include <string>
#include <fstream>
#include "Storage/GeneralMatrix.hpp"

namespace Tuna {

template <typename T>  class SparseMatrix;
  
/*!
 *  This structure is used to set the precision, that can be \c float,
 *  \c double and \c long double, as well as the dimension of the problem.
 */  
template <typename T>  
struct Typeinfo <SparseMatrix<T> > {
  typedef typename Typeinfo<T>::prec_t prec_t;
  enum { Dim = Typeinfo<T>::Dim };
};

/*! 
 ***************************************************************************
 * General sparse matrices.
 * This is a general class for sparse matrices. The template parameter is
 * and adaptor used to control the behavior of the SparseMatrix<> objects.
 ***************************************************************************
 *  \author  Luis M. de la Cruz [ Sun Oct 28 17:18:28 GMT 2011 ]
 ***************************************************************************
 */
template<typename Tadaptor>
class SparseMatrix : public GeneralMatrix<SparseMatrix<Tadaptor> > {

public:
  
/*! Precision for all calculations. */
  typedef typename Typeinfo<Tadaptor>::prec_t prec_t;
/*! Array of ints to define extents. */        
  typedef typename TunaArray<int, Typeinfo<Tadaptor>::Dim >::tiny intTinyArray_t;
/*! Array of floats to define the deltas in each axis. */        
  typedef typename TunaArray<prec_t, Typeinfo<Tadaptor>::Dim >::tiny floatTinyArray_t;
/*! Arrays for numbers.*/
  typedef typename TunaArray<prec_t,1>::huge ScalarField1D;

  SparseMatrix();  
  SparseMatrix(unsigned int e1);
  SparseMatrix(unsigned int e1, unsigned int e2);
  SparseMatrix(unsigned int e1, unsigned int e2, unsigned int e3);
  SparseMatrix(const SparseMatrix& other);
  ~SparseMatrix() {}
    
// The Curiously Recurring Template Pattern (CRTP).
  Tadaptor& asDerived() { return static_cast<Tadaptor&>(*this); }

  inline void resize(unsigned int e1);
  inline void resize(unsigned int e1, unsigned int e2);
  inline void resize(unsigned int e1, unsigned int e2, unsigned int e3);
    
/*!
 *  Function to calculate the points of the mesh, implemented in the adaptor.
 */    
//  inline bool calcPoints() { return asDerived().calcPoints(); }

/*!
 *  Make a matrix equal to other existing matrix.
 */
  SparseMatrix<Tadaptor>& operator=(const SparseMatrix<Tadaptor>& other);
    
  bool print(bool flag);

  string getName() { return asDerived().getName();  }

protected:


private:

};

/*!
 *  Default constructor.
 */
template<typename Tadaptor>
SparseMatrix<Tadaptor>::SparseMatrix() {
  asDerived().allocateMemory();
}

/*!
 *  Constructor for 1D.
 *  \param e1 number of nodes in the x-axis.
 */
template<typename Tadaptor>
SparseMatrix<Tadaptor>::SparseMatrix(unsigned int e1) {
  asDerived().allocateMemory(e1);
}

/*!
 *  Constructor for 2D.
 *  \param e1 number of nodes in the x-axis.
 *  \param e2 number of nodes in the y-axis.
 */
template<typename Tadaptor>
SparseMatrix<Tadaptor>::SparseMatrix(unsigned int e1, 
				     unsigned int e2) {
  asDerived().allocateMemory(e1, e2);
}

/*!
 *  Constructor for 3D.
 *  \param e1 number of nodes in the x-axis.
 *  \param e2 number of nodes in the y-axis.
 *  \param e3 number of nodes in the z-axis.
 */    
template<typename Tadaptor>
SparseMatrix<Tadaptor>::SparseMatrix(unsigned int e1, 
				     unsigned int e2, 
				     unsigned int e3) {
  asDerived().allocateMemory(e1, e2, e3);
}

/*!
 *  Copy constructor.
 */
template<typename Tadaptor>
SparseMatrix<Tadaptor>::SparseMatrix(const SparseMatrix<Tadaptor>& other) 
{
  asDerived().copyMatrix(other);
}

/*!
 *  Resize the matrix in 1D.
 *  \param e1 number of nodes in the x-axis.
 */
template<typename Tadaptor>
inline void SparseMatrix<Tadaptor>::resize(unsigned int e1) {
  asDerived().resize(e1);
}

/*!
 *  Resize the matrix in 2D.
 *  \param e1 number of nodes in the y-axis.
 *  \param e2 number of nodes in the z-axis. 
 */
template<typename Tadaptor>
inline void SparseMatrix<Tadaptor>::resize(unsigned int e1, 
					   unsigned int e2) {
  asDerived().resize(e1, e2);
}

/*!
 *  Resize the matrix in 3D.
 *  \param e1 number of nodes in the x-axis.
 *  \param e2 number of nodes in the y-axis.
 *  \param e3 number of nodes in the z-axis.
 */
template<typename Tadaptor>
inline void SparseMatrix<Tadaptor>::resize(unsigned int e1, 
					   unsigned int e2, 
					   unsigned int e3) {
  asDerived().resize(e1, e2, e3);
}

/*!
 *  Asignation operator.
 */
template<typename Tadaptor>
SparseMatrix<Tadaptor>& SparseMatrix<Tadaptor>::operator=
(const SparseMatrix<Tadaptor>& other) {
  if (this != &other) {
    asDerived().assignMatrix(other);
  } else {
    std::cout << "\n +-----+" 
	      << "\n | Tuna::SparseMatrix::operator= : "
	      <<" \n | WARNING : you are trying to do : mesh = mesh"
	      << "\n +-----+";
  }
  return *this;
}

/*!
 *  Print the info of the mesh on to the screen.
 */
template<typename Tadaptor>
bool SparseMatrix<Tadaptor>::print(bool flag) {

  std::cout << "\n +----- TUNA info -----+"
	    << "\n | SparseMatrix< ";
  asDerived().print();
  std::cout << "\n | (rows, cols) = (" <<  this->rows << ", " << this->cols << ") \n" ;

  if(flag) {
    std::cout << this->store;
  }
  std::cout << "\n +---------------------+\n ";



  return 0;
}


} // Tuna namespace

#endif // _SPARSEMATRIX_H
